home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
C++
/
Frameworks
/
Sprocket Framework DR2
/
Sprocket Framework
/
MenuBar.cp
< prev
next >
Wrap
Text File
|
1996-06-15
|
13KB
|
601 lines
/*
File: MenuBar.cp
Project: Sprocket Framework 1.1 (DR2), released 6/15/96
Contains: A MenuBar class deliberately designed to resemble ODMenuBar from OpenDoc™
To Do: ?
Sprocket Major Contributors:
----------------------------
Dave Falkenburg, producer of Sprocket 1.0
Bill Hayden, producer of Sprocket 1.1
Steve Sisak, producer of the upcoming Sprocket 2.0
Pete Alexander Steve Falkenburg Randy Thelen
Eric Berdahl Nitin Ganatra Chris K. Thomas
Marshall Clow Dave Hershey Leonard Rosenthal
Tim Craycroft Dave Mark Dean Yu
David denBoer Gary Powell
Cameron Esfahani Jon Summers Apple Computer, Inc.
Comments, Additions, or Corrections:
------------------------------------
Bill Hayden, Nikol Software <nikol@codewell.com>
*/
#include "MenuBar.h"
#include "Sprocket.h"
#include "StandardMenus.h"
Boolean TMenuBar::fgMenuBarNeedsRedraw = true;
Boolean TMenuBar::fgMenuBarHidden = false;
short TMenuBar::fgMenuBarHeight = 20;
RgnHandle TMenuBar::fgMenuBarRgn = nil;
inline UInt32 BuildKey(UInt16 hiword, UInt16 loword)
{
return (((UInt32) hiword << 16) | loword);
}
TMenuItemTable::CompareResult
TMenuItemTable::Compare(ArrayElementPtr element1,ArrayElementPtr element2)
{
UInt32 key1 = BuildKey(((MenuMapping *) element1)->fMenu, ((MenuMapping *) element1)->fItem);
UInt32 key2 = BuildKey(((MenuMapping *) element2)->fMenu, ((MenuMapping *) element2)->fItem);
return (key2 - key1);
}
TMenuCommandTable::CompareResult
TMenuCommandTable::Compare(ArrayElementPtr element1, ArrayElementPtr element2)
{
return (((MenuMapping *) element2)->fCommand - ((MenuMapping *) element1)->fCommand);
}
/*****************************************************************************/
OSErr TMenuBar::GetNewMenuBar(short whichMBAR)
{
MenuBarResource ** mbarResource = (MenuBarResource **) GetResource('MBAR', whichMBAR);
if (mbarResource)
{
UInt16 menuCount;
fCurrentMBAR = whichMBAR;
HLock((Handle) mbarResource);
menuCount = (**mbarResource).numberOfMenus;
fgMenuBarHeight = GetMBarHeight();
for (UInt16 menuIndex = 0; menuIndex < menuCount; menuIndex++)
{
SInt16 whichMenu = (**mbarResource).menuIDList[menuIndex];
MenuRef theMenu;
// try to make the MenuRef from a 'CMNU' which allows us to
// automatically register any commands we find in the resource.
theMenu = this->GetMenuFromCMNU(whichMenu);
if (theMenu == NULL)
{
// no 'CMNU' was found, so go ahead and use a 'MENU'
// resource, knowing that we must register commands
// manually.
theMenu = GetMenu(whichMenu);
}
// Add the menu to the end of the menubar
if (theMenu)
InsertMenu(theMenu, 0);
else
return resNotFound;
}
// force a redraw of the menubar at the next possible opportunity
fgMenuBarNeedsRedraw = true;
HUnlock((Handle) mbarResource);
ReleaseResource((Handle) mbarResource);
}
else
return resNotFound;
return noErr;
}
/*****************************************************************************/
// Define some functions to help us walk through CMNU resources
// (this should make the code a bit more readable)
static CommandID *FindMenuCommandPtrFromCMNUItem(CMNUItemData *currentItem);
static CMNUItemData *FindNextCMNUItem(CMNUItemData *currentItem);
static CommandID *FindMenuCommandPtrFromCMNUItem(CMNUItemData *currentItem)
{
Byte * p = (Byte *) currentItem;
if ((*p) == NULL) // we’re at the end of the CMNU!
return NULL;
p += (*p) + 1 // itemString[0], a.k.a. the length
+ sizeof(Byte) // itemIcon
+ sizeof(Byte) // itemCmd
+ sizeof(Byte) // itemMark
+ sizeof(Style); // itemStyle
p = (Byte *) ((((long) p) + 1) & ~1); // align up to the next even boundary
return (CommandID *) p;
}
static CMNUItemData *FindNextCMNUItem(CMNUItemData *currentItem)
{
return (CMNUItemData *)(FindMenuCommandPtrFromCMNUItem(currentItem) + 1);
}
/*****************************************************************************/
MenuRef TMenuBar::GetMenuFromCMNU(short whichMenu)
{
CMNUResource ** theCMNU = (CMNUResource **) GetResource('CMNU', whichMenu);
MenuRef newMenuRef = NULL;
if (theCMNU)
{
HLock((Handle) theCMNU);
MenuID theMenuID = (**theCMNU).menuID;
MenuItemID itemNum = 1;
CommandID theCommand;
short cmdChar;
if(whichMenu != theMenuID)
DebugMessage("\pSprocket has encountered a non-matching menu resource ID and menu ID.");
// Make a new MenuRef from the CMNU data
newMenuRef = NewMenu(theMenuID, (**theCMNU).menuTitle);
// MENU & CMNU resources suck, don’t they?
Byte * p = (Byte *) (**theCMNU).menuTitle;
// Don’t forget to skip past string and length byte
p += *p + 1;
CMNUItemData * theItemData = (CMNUItemData *) p;
while (theItemData->itemString[0]) // do we have any menu items
{
p = (Byte *) theItemData;
p += *p + 1;
// use the item data to build a new menuitem
::AppendMenu(newMenuRef, theItemData->itemString);
::SetItemIcon(newMenuRef, itemNum, *p++);
::SetItemCmd(newMenuRef, itemNum, *p++);
::SetItemMark(newMenuRef, itemNum, *p++);
::SetItemStyle(newMenuRef, itemNum, *p++);
// deal with any disabled items
if (!((**theCMNU).enableFlags & (1 << itemNum)))
DisableItem(newMenuRef,itemNum);
// align up to the next even boundary
p = (Byte *) ((((long) p) + 1) & ~1);
// register the menu command, if any
theCommand = *((CommandID *) p);
if (theCommand)
this->RegisterCommand(theCommand, theMenuID, itemNum);
// insert a submenu if this item has one
::GetItemCmd(newMenuRef, itemNum, &cmdChar);
if (cmdChar == hMenuCmd)
{
MenuRef aSubmenu;
::GetItemMark(newMenuRef, itemNum, &cmdChar);
aSubmenu = GetMenuFromCMNU(cmdChar);
if (!aSubmenu)
aSubmenu = GetMenu(cmdChar);
if (aSubmenu)
::InsertMenu(aSubmenu, -1);
else
DebugMessage("\pNon-existant submenu specified in TMenuBar::GetMenuFromCMNU");
}
theItemData = FindNextCMNUItem(theItemData);
itemNum++;
}
ReleaseResource((Handle) theCMNU);
}
return newMenuRef;
}
/*****************************************************************************/
// find the menu command in the array, given the menu and item
CommandID TMenuBar::GetCommand(MenuID menu, MenuItemID item)
{
MenuMapping key = {menu, item, kNoMenuCommandID};
MenuMapping * foundMapping;
foundMapping = (MenuMapping *) fMenuItemTable.Find(&key);
if (foundMapping)
return foundMapping->fCommand;
return kNoMenuCommandID;
}
/*****************************************************************************/
// find the menu and item in the array, given the menu command
void TMenuBar::GetMenuAndItem(CommandID commandNum,
MenuID * returnedMenu,
MenuItemID * returnedItem)
{
MenuMapping key = {kNoMenuID,kNoMenuItemID,commandNum};
MenuMapping * foundMapping;
foundMapping = (MenuMapping *) fCommandTable.Find(&key);
if (foundMapping)
{
*returnedMenu = foundMapping->fMenu;
*returnedItem = foundMapping->fItem;
}
else
{
*returnedMenu = kNoMenuID;
*returnedItem = kNoMenuItemID;
}
}
/*****************************************************************************/
OSErr TMenuBar::RegisterCommand(CommandID commandNum, MenuID menu, MenuItemID item)
{
MenuMapping * aMapping = new MenuMapping;
if (aMapping == NULL)
return MemError();
aMapping->fMenu = menu;
aMapping->fItem = item;
aMapping->fCommand = commandNum;
fCommandTable.Add(aMapping);
fMenuItemTable.Add(aMapping);
return noErr;
}
/*****************************************************************************/
OSErr TMenuBar::UnregisterCommand(CommandID commandNum)
{
MenuMapping key = {kNoMenuID, kNoMenuItemID, commandNum};
return noErr;
}
/*****************************************************************************/
MenuRef TMenuBar::GetMenuRefAndItemFromCommand(CommandID commandNum, MenuID *menu, MenuItemID *item)
{
this->GetMenuAndItem(commandNum, menu, item);
if (*menu != kNoMenuID)
return GetMenuHandle(*menu);
else
return NULL;
}
/*****************************************************************************/
void TMenuBar::EnableCommand(CommandID commandNum, Boolean enable)
{
MenuRef menuHandle;
MenuID menu;
MenuItemID item;
menuHandle = this->GetMenuRefAndItemFromCommand(commandNum, &menu, &item);
if (menuHandle)
{
if (enable)
EnableItem(menuHandle, item);
else
DisableItem(menuHandle,item);
}
}
/*****************************************************************************/
void TMenuBar::EnableAndCheckCommand(CommandID commandNum, Boolean enable, Boolean check)
{
MenuRef menuHandle;
MenuID menu;
MenuItemID item;
menuHandle = this->GetMenuRefAndItemFromCommand(commandNum, &menu, &item);
if (menuHandle)
{
CheckItem(menuHandle, item, check);
if (enable)
EnableItem(menuHandle, item);
else
DisableItem(menuHandle, item);
}
}
/*****************************************************************************/
void TMenuBar::GetItemString(CommandID commandNum, StringPtr itemString)
{
MenuRef menuHandle;
MenuID menu;
MenuItemID item;
menuHandle = this->GetMenuRefAndItemFromCommand(commandNum, &menu, &item);
if (menuHandle)
GetMenuItemText(menuHandle, item, itemString);
}
/*****************************************************************************/
void TMenuBar::SetItemString(CommandID commandNum, StringPtr itemString)
{
MenuRef menuHandle;
MenuID menu;
MenuItemID item;
menuHandle = this->GetMenuRefAndItemFromCommand(commandNum, &menu, &item);
if (menuHandle)
SetMenuItemText(menuHandle, item, itemString);
}
/*****************************************************************************/
void TMenuBar::SetItemStyle(CommandID commandNum, Style aStyle)
{
MenuRef menuHandle;
MenuID menu;
MenuItemID item;
menuHandle = this->GetMenuRefAndItemFromCommand(commandNum, &menu, &item);
if (menuHandle)
::SetItemStyle(menuHandle, item, aStyle);
}
/*****************************************************************************/
void TMenuBar::RedrawIfNeeded()
{
if (fgMenuBarNeedsRedraw && !fgMenuBarHidden)
{
DrawMenuBar();
fgMenuBarNeedsRedraw = false;
}
}
/*****************************************************************************/
void TMenuBar::Invalidate()
{
fgMenuBarNeedsRedraw = true;
}
/*****************************************************************************/
void TMenuBar::Validate()
{
fgMenuBarNeedsRedraw = false;
}
/*****************************************************************************/
void TMenuBar::HideMenuBar()
{
Rect mBarRect;
if (fgMenuBarHidden) // It was already hidden
return;
LMSetMBarHeight(0); // make the Menu Bar's height zero
fgMenuBarRgn = NewRgn();
mBarRect = qd.screenBits.bounds; // create a rect for the mbar
mBarRect.bottom = mBarRect.top + fgMenuBarHeight;
RectRgn(fgMenuBarRgn, &mBarRect); // make a region for the mbar
RgnHandle GrayRgn = LMGetGrayRgn();
UnionRgn(GrayRgn,fgMenuBarRgn,GrayRgn); // tell the desktop it covers the menu bar
WindowRef wpFirst = LMGetWindowList();
PaintBehind(wpFirst, fgMenuBarRgn); // redraw windows behind front
CalcVisBehind(wpFirst, fgMenuBarRgn); // redraw windows behind front
fgMenuBarHidden = true;
}
/*****************************************************************************/
void TMenuBar::ShowMenuBar()
{
RgnHandle GrayRgn = LMGetGrayRgn();
if (fgMenuBarRgn) // i.e. HideMenuBar has already been called
{
LMSetMBarHeight(fgMenuBarHeight); // make the menu bar's height normal
DiffRgn(GrayRgn, fgMenuBarRgn, GrayRgn); // remove the menu bar from the desktop
DisposeRgn(fgMenuBarRgn); // dispose the bar region
}
DrawMenuBar();
fgMenuBarNeedsRedraw = false;
fgMenuBarHidden = false;
}
/*****************************************************************************/
OSErr TMenuBar::HiliteMenusForModalDialog(Boolean hiliting)
{
MenuBarResource ** mbarResource = (MenuBarResource **) GetResource('MBAR', fCurrentMBAR);
if (mbarResource)
{
UInt16 menuCount;
this->EnableCommand( cAbout, hiliting ); // Leave DA's active, as they should be
HLock((Handle) mbarResource);
menuCount = (**mbarResource).numberOfMenus;
for (short menuIndex = 0; menuIndex < menuCount; menuIndex++)
{
MenuRef theMenu;
SInt16 whichMenu;
whichMenu = (**mbarResource).menuIDList[menuIndex];
if (whichMenu == mApple) // Apple menu already handled
continue;
theMenu = GetMenuHandle(whichMenu);
// Enable or disable the menu as appropriate
if (theMenu)
{
if (hiliting)
EnableItem(theMenu, 0);
else
{
if (whichMenu == mEdit)
{
for (short x = 1; x <= CountMItems(theMenu); x++)
{
DisableItem(theMenu, x);
}
}
else
DisableItem(theMenu, 0);
}
}
else
return resNotFound;
}
// force a redraw of the menubar at the next possible opportunity
fgMenuBarNeedsRedraw = true;
HUnlock((Handle) mbarResource);
ReleaseResource((Handle) mbarResource);
}
else
return resNotFound;
return noErr;
}